package com.lang.classloader;

import com.sun.nio.zipfs.ZipInfo;
import com.sun.reflect.RflectionDemo;
import org.apache.commons.logging.impl.Log4JLogger;
import org.junit.Test;
import sun.nio.cs.ext.Big5;

import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;
import java.util.logging.Logger;

public class ClassloaderDemo {

    /**
     * 查看某个类加载器加载的类
     */
    @Test
    public  void getClassLoaderLoadClasses() throws IllegalAccessException, NoSuchFieldException {
//    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
        Field f=ClassLoader.class.getDeclaredField("classes");
        f.setAccessible(true);
        f.get(ClassLoader.getSystemClassLoader());
        Vector classes=(Vector)f.get(ClassLoader.getSystemClassLoader());
        System.out.println("当前系统加载器加载的class："+classes.toString());

        System.out.println(ClassLoader.getSystemClassLoader().equals(Thread.currentThread().getContextClassLoader()));
    }


    /**
     * 验证各个类加载器的父子关系，类加载器之间不是使用继承的关系，使用的是组合关系，即子类加载器通过parent属性引用了父加载器
     */
    @Test
    public void getClassLoaderParent(){
        URLClassLoader urlClassLoader = new URLClassLoader(new URL[]{});
        System.out.println("自定义的类加载器的父加载器："+urlClassLoader.getParent());
        System.out.println("自定义的类加载器的爷爷加载器："+urlClassLoader.getParent().getParent());
        System.out.println("自定义的类加载器的太爷爷加载器："+urlClassLoader.getParent().getParent().getParent());
    }

    /**
     * 获取各个类加载器的环境变量
     *
     * 编译完成后，使用这个命令执行，使用idea会出现classpath大于bootclasspath的情况，发现bootclasspath会加载jar包内的class，然而文件夹下面的class文件没有加载，要等到classpath去加载
     * D:\java\jre8\bin\java.exe -Xbootclasspath/p:D:\project\javastudy\out\production\javastudy\com\sun\reflect;D:\java\jre8\jre\lib\charsets.jar;D:\project\javastudy\lib\commons-logging-1.2.jar; "-javaagent:D:\IntelliJ IDEA 2018.1.2\lib\idea_rt.jar=60177:D:\IntelliJ IDEA 2018.1.2\bin" -Dfile.encoding=UTF-8 -classpath "D:\java\jre8\jre\lib\charsets.jar;D:\project\javastudy\lib\commons-logging-1.2.jar;" com.lang.classloader.ClassloaderDemo
     *
     result
     sun.misc.Launcher$AppClassLoader@18b4aac2
     D:\project\javastudy\out\production\javastudy\com\sun\reflect;D:\java\jre8\jre\lib\charsets.jar;;D:\java\jre8\jre\lib\resources.jar;D:\java\jre8\jre\lib\rt.jar;D:\java\jre8\jre\lib\sunrsasign.jar;D:\java\jre8\jre\lib\jsse.jar;D:\java\jre8\jre\lib\jce.jar;D:\java\jre8\jre\lib\charsets.jar;D:\java\jre8\jre\lib\jfr.jar;D:\java\jre8\jre\classes
     sun.misc.Launcher$AppClassLoader@18b4aac2
     null
     null
     null
     */
//    @Test
//    public void test01() throws IOException {
    public static void main(String[] args) {
        ClassLoader classLoader =ClassloaderDemo.class.getClassLoader();
        System.out.println(classLoader);
//        System.out.println(classLoader.getResource(""));
        /**
         * 获取bootstrap类的加载路径
         */
        System.out.println("bootstrap Classloader : "+System.getProperty("sun.boot.library.path"));
        System.out.println("bootstrap Classloader : "+System.getProperty("sun.boot.class.path"));

        System.out.println("ext Classloader : "+System.getProperty("java.ext.dirs"));
        System.out.println("用户自定义的类由系统类加载器加载："+RflectionDemo.class.getClassLoader());
        System.out.println("第三方jar包中的类由系统类加载器加载："+Log4JLogger.class.getClassLoader());
        System.out.println("扩展包中的类由extClassLoader加载:"+ZipInfo.class.getClassLoader());
        System.out.println("虚拟机核心类由Bootstrap ClassLoader加载:"+ BigDecimal.class.getClassLoader());

    }

    /**
     * 使用不同类加载器加载同一个class文件，并初始化，发现其静态属性被初始化两次且不相等。所以不同的classLoader加载相同class文件后虚拟机中是两个不同的类，即使两个类路径与名称一致，但其ClassLoader不同（可以理解为不同的namespace）。
     */
    @Test
    public void sameClassNameButNoOnClass() throws  NoSuchMethodException, InvocationTargetException, IllegalAccessException, ClassNotFoundException {
        String rootDir="E:\\project\\javastudy\\out\\production\\javastudy";
        //创建自定义文件类加载器
        FileClassLoader loader1 = new FileClassLoader(rootDir);
        FileClassLoader loader2 = new FileClassLoader(rootDir);
        //这里不适用loadClass，因为这个类已经被父加载器加载过了，所以使用findClass，强制将该类加载到两个不同加载器中，也可以将其从classPath中删除，然后从别的rootDir中进行加载。
        Class<?> class1=loader1.findClass("com.lang.classloader.OneClassFileTwoClassObject");
        Class<?> class2=loader2.findClass("com.lang.classloader.OneClassFileTwoClassObject");

        Method class1Method = class1.getMethod("getInstance");
        Method class2Method = class2.getMethod("getInstance");

        //两个类中的静态变量
        Object class1StaticField = class1Method.invoke(class1);
        Object class2StaticField = class2Method.invoke(class2);
        System.out.println(class1.equals(class2));
        System.out.println(class1StaticField.equals(class2StaticField));



    }


    /**
     * 使用extClassLoader加载类?
     */
    @Test
    public void test03() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
        ClassLoader extClassLoader = ClassLoader.getSystemClassLoader().getParent();
//        ClassLoader extClassLoader = ClassLoader.getSystemClassLoader();
        Class clazz = extClassLoader.loadClass("com.sun.reflect.RflectionDemo");
        Object object = clazz.newInstance();
        Method method = clazz.getMethod("testGetCallerClass",null);
        method.invoke(object);
        System.out.println(clazz.getClassLoader());
    }



}
